package ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.factories.imp;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import net.wimpi.modbus.procimg.SimpleDigitalIn;
import net.wimpi.modbus.procimg.SimpleDigitalOut;
import net.wimpi.modbus.procimg.SimpleInputRegister;
import net.wimpi.modbus.procimg.SimpleRegister;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.devicecontroller.DeviceManager;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.devicecontroller.ProcessImageDated;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.devicecontroller.factories.DeviceManagerFactory;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.DeviceDAO;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.AddressValue;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Alarm;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.CompoundCommand;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Device;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Field;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.SimpleCommand;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.AlarmService;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.CompoundCommandService;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.DeviceService;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.FieldService;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.SimpleCommandService;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.factories.AlarmServiceFactory;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.factories.CompoundCommandServiceFactory;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.factories.DeviceServiceFactory;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.factories.FieldServiceFactory;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.factories.SimpleCommandServiceFactory;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.service.imp.DeviceServiceImp;

@Component
public class DeviceServiceFactoryImp implements DeviceServiceFactory {

	//TODO: Completo
	@Autowired(required = true)
	private DeviceManagerFactory devicemanfactory;
	@Autowired(required = true)
	private AlarmServiceFactory alarmfactory;
	@Autowired(required = true)
	private CompoundCommandServiceFactory compfactory;
	@Autowired(required = true)
	private SimpleCommandServiceFactory simplefactory;
	@Autowired(required = true)
	private FieldServiceFactory fieldfactory;
	@Autowired(required = true)
	private DeviceDAO deviceDAO;
	
	@Override
	public DeviceService create(Device device) {
		DeviceServiceImp ret = new DeviceServiceImp();
		
		ret.setDevice(device);

		DeviceManager deviceman = devicemanfactory.create(device);
		deviceman.addDeviceChangeListener(ret);
		ret.setDeviceman(deviceman);
		
		ProcessImageDated image = deviceman.getProcessImage();
		
		List<Field> fields = deviceDAO.getFields(device);
		
		for (Field field : fields) {
			AddressValue lastVal = deviceDAO.getLastAddressValue(device,field.getAddress(),field.getAddressType());
			if(lastVal != null){
				switch(lastVal.getAddressType()){
				case COIL:
					image.setDigitalOut(field.getAddress(), new SimpleDigitalOut(lastVal.getValue() == 1), lastVal.getDate());
					break;
				case DISCRETE:
					image.setDigitalIn(field.getAddress(), new SimpleDigitalIn(lastVal.getValue() == 1), lastVal.getDate());
					break;
				case HOLDING_REGISTER:
					image.setRegister(field.getAddress(), new SimpleRegister(lastVal.getValue()), lastVal.getDate());
					break;
				case INPUT_REGISTER:
					image.setInputRegister(field.getAddress(), new SimpleInputRegister(lastVal.getValue()), lastVal.getDate());
					break;
				default:
					break;
				}
				
			}
		}
		
		List<FieldService> fieldServices = new ArrayList<FieldService>();
		fieldServices.addAll(fieldfactory.create(fields,device,image));
		ret.setFieldsService(fieldServices);
		
		HashMap<Integer,FieldService> fieldServicesMap = new HashMap<Integer, FieldService>();
		
		for (Iterator<FieldService> iterator = fieldServices.iterator(); iterator.hasNext();) {
			FieldService fieldService = (FieldService) iterator.next();
			fieldServicesMap.put(fieldService.getID(), fieldService);
		}
		
		List<Alarm> devalarms = deviceDAO.getAlarms(device);
		List<AlarmService> alarmServices = new ArrayList<AlarmService>();
		alarmServices.addAll(alarmfactory.create(devalarms,device,fieldServicesMap));
		ret.setActiveDeviceAlarmsService(alarmServices);
		
		List<CompoundCommand> commands = deviceDAO.getCompoundCommands(device);
		List<CompoundCommandService> compoundCommandService = new ArrayList<CompoundCommandService>();
		compoundCommandService.addAll(compfactory.create(commands,device));
		ret.setCompoundCommandsService(compoundCommandService);
		
		List<SimpleCommand> commandsSimp = deviceDAO.getSimpleCommands(device);
		List<SimpleCommandService> simpleCommandServices = new ArrayList<SimpleCommandService>();
		simpleCommandServices.addAll(simplefactory.create(commandsSimp,device));
		ret.setSimpleCommandsService(simpleCommandServices);
		
		ret.setDevDAO(deviceDAO);
		
		return ret;
	}


	/**
	 * @return the devicemanfactory
	 */
	public DeviceManagerFactory getDevicemanfactory() {
		return devicemanfactory;
	}

	/**
	 * @param devicemanfactory the devicemanfactory to set
	 */
	public void setDevicemanfactory(DeviceManagerFactory devicemanfactory) {
		this.devicemanfactory = devicemanfactory;
	}

	/**
	 * @return the alarmfactory
	 */
	public AlarmServiceFactory getAlarmfactory() {
		return alarmfactory;
	}

	/**
	 * @param alarmfactory the alarmfactory to set
	 */
	public void setAlarmfactory(AlarmServiceFactory alarmfactory) {
		this.alarmfactory = alarmfactory;
	}

	/**
	 * @return the compfactory
	 */
	public CompoundCommandServiceFactory getCompfactory() {
		return compfactory;
	}

	/**
	 * @param compfactory the compfactory to set
	 */
	public void setCompfactory(CompoundCommandServiceFactory compfactory) {
		this.compfactory = compfactory;
	}

	/**
	 * @return the simplefactory
	 */
	public SimpleCommandServiceFactory getSimplefactory() {
		return simplefactory;
	}

	/**
	 * @param simplefactory the simplefactory to set
	 */
	public void setSimplefactory(SimpleCommandServiceFactory simplefactory) {
		this.simplefactory = simplefactory;
	}

	/**
	 * @return the fieldfactory
	 */
	public FieldServiceFactory getFieldfactory() {
		return fieldfactory;
	}

	/**
	 * @param fieldfactory the fieldfactory to set
	 */
	public void setFieldfactory(FieldServiceFactory fieldfactory) {
		this.fieldfactory = fieldfactory;
	}


	/**
	 * @return the deviceDAO
	 */
	public DeviceDAO getDeviceDAO() {
		return deviceDAO;
	}


	/**
	 * @param deviceDAO the deviceDAO to set
	 */
	public void setDeviceDAO(DeviceDAO deviceDAO) {
		this.deviceDAO = deviceDAO;
	}

}
